<!--  ERC-设备管理-设备台账页面-树形弹窗页面弹窗页面 -->
<template>
  <px-dialog
    v-model="TreedialogVisible"
    class="equip-dialog"
    title="添加巡检位置"
    height="500px"
    width="800px"
    @open="openDialog"
    @close="closeDialog"
  >
    <div v-loading="done" class="equip-tree-wrap">
      <div class="container">
        <px-row :gutter="20">
          <!-- 左侧树形结构 -->
          <px-col :span="12" style="height: 400px; overflow-y: auto">
            <div class="equip-tree-content">
              <px-input v-model="filterTextLeft" style="margin-right: 6px" placeholder="请输入关键字搜索" clearable />
              <px-tooltip content="全部收折" placement="top">
                <px-button v-show="isTreeOpen" link type="primary" icon="ChevronUpRectangle" @click="openOrCloseTreeLeft('close')" />
              </px-tooltip>
              <px-tooltip content="全部展开" placement="top">
                <px-button v-show="!isTreeOpen" link type="primary" icon="ChevronDownRectangle" @click="openOrCloseTreeLeft('open')" />
              </px-tooltip>
            </div>
            <px-tree-v2
              ref="treeRef"
              :check-strictly="true"
              :data="treeDataLeft"
              show-checkbox
              node-key="id"
              :props="treeConfig"
              :default-checked-keys="defaultCheckedKeys"
              :filter-method="filterNode"
              :expand-on-click-node="false"
              :height="350"
              @check="handleCheck"
            >
              <template #default="{ data }">
                <div class="flex justify-center items-center w-[150px]">
                  <px-icon v-if="data.eqpType == 'MONITOR'" class="flex justify-center"><Camera /></px-icon>
                  <ReTextTooltip :content="data.type !== 'EQP' ? data.name : `${data.code}/${data.name}`" />
                </div>
              </template>
            </px-tree-v2>
          </px-col>
          <!-- 右侧表格 -->
          <px-col :span="12" style="height: 400px; overflow-y: auto">
            <div style="display: flex; align-items: center; justify-content: space-between; font-size: 14px; color: rgb(0 0 0 / 80%)">
              <div>
                已选:<span style="color: #3b82f6"> {{ checkedNodesArr.length }}</span>
              </div>
              <px-button link type="primary" style="margin-left: 5px" @click="clearSelection">清除</px-button>
            </div>
            <px-table ref="multipleTableRef" :data="checkedNodesArr" :border="false" class="no-border-table" style="width: 100%" :show-header="false">
              <px-table-column prop="zhPath" />
              <px-table-column width="100" align="right">
                <template #default="{ $index }">
                  <px-tooltip content="删除" placement="top">
                    <px-button link size="small" icon="Close" @click="handleDelete($index)" />
                  </px-tooltip>
                </template>
              </px-table-column>
            </px-table>
          </px-col>
        </px-row>
        <!-- 底部 -->
        <div class="equip-dialog-footer">
          <px-button @click="closeDialog">取消</px-button>
          <px-button type="primary" :loading="isLoading" @click="handleSubmit()">保存</px-button>
        </div>
      </div>
    </div>
  </px-dialog>
</template>
<script setup lang="ts">
import { ref, reactive, toRefs, computed, watch, nextTick } from "vue";
import { PxMessage, PxTable } from "px-ui";
import { queryFacPositionTree } from "@/api/visual/module";
import { saveOrUpdateBatch, delTableId } from "@/api/visual/inspection";
import ReTextTooltip from "@/components/ReTextTooltip";
import { setItem, getItem, isObjEmpty } from "../../template/utils";
import { cloneDeep } from "@pureadmin/utils";
import { useRoute } from "vue-router";

const route = useRoute();

// 调用父级-关闭弹窗、查询列表方法
const emits = defineEmits(["closeDialog", "addEquipGroupSelect", "queryTreeRight"]);
const TreedialogVisible = defineModel("TreedialogVisible");
// 父级传过来的值
const props = defineProps({
  routeCode: {
    type: String,
    default: ""
  },
  selected: {
    type: Array,
    default: () => []
  }
});

// 页面本身的值
const treeRef = ref(null);
const isLoading = ref(false);
const done = ref(false);
const multipleTableRef = ref<InstanceType<typeof PxTable>>();
const state = reactive<any>({
  filterTextLeft: "",
  isTreeOpen: true,
  defaultCheckedKeys: [],

  treeDataLeft: []
});

const { filterTextLeft, isTreeOpen, defaultCheckedKeys, treeDataLeft } = toRefs(state);
let checkedNodesArr = ref([]);
const treeConfig = {
  children: "children",
  value: "code",
  label: "name",
  key: "code",
  disabled: "disabled"
};

let globalClassName = JSON.parse(localStorage.getItem("classList"));
if (globalClassName?.length > 0) {
  const res = [];
  globalClassName.forEach(item => {
    res.push(item.code);
  });
  globalClassName = res;
}
watch(filterTextLeft, val => {
  treeRef.value!.filter(val);
});
watch(
  () => [props.TreedialogVisible, props.selected, treeRef.value, treeDataLeft.value],
  () => {
    if (props.TreedialogVisible && props.selected.length > 0 && treeRef.value && treeDataLeft.value.length > 0) {
      let res: any = [];
      let defaultExpendeKeys = collectValues(treeDataLeft.value, "code", 2);
      defaultExpendeKeys = defaultExpendeKeys.filter(item => item.includes("BUILD") || item.includes("FAC"));
      props.selected.forEach(item => {
        res.push(item.itemCode);
      });
      setTimeout(async () => {
        treeRef.value.setCheckedKeys(res);
        await nextTick(() => {});
        treeRef.value.setExpandedKeys(res.concat(defaultExpendeKeys));

        // const nodes = treeRef.value.getCheckedNodes();
        if (props.selected && props.selected.length > 0) {
          checkedNodesArr.value = cloneDeep(props.selected);
        }
      }, 0);
    } else if (props.TreedialogVisible && treeRef.value && treeDataLeft.value.length > 0) {
      let defaultExpendeKeys = collectValues(treeDataLeft.value, "code", 2);
      treeRef.value.setExpandedKeys(defaultExpendeKeys);
    }
  },
  {
    immediate: true
  }
);
let treeDataLeftFltter = {};
// 进入页面加载树
const queryTree = async () => {
  const facCode = localStorage.getItem("facCode");
  const lSItem = `visual_index_inspection_tree_${facCode}`;
  let data = [];
  data = JSON.parse(await getItem(lSItem, "[]"));
  if (data.length == 0 || route.query.noCache) {
    data = (await queryFacPositionTree({
      facCode,
      containMonitor: true,
      needEqp: true,
      name: ""
    })) as any;

    try {
      await setItem(lSItem, JSON.stringify(data), 24, "h");
    } catch (error) {
      console.log(error);
    }
  }

  treeDataLeft.value = filterTree(data, "ROOM", { className: globalClassName });
  // 判断节点是否可选择
  const filterNodeIsChecked = node => {
    if ((node.eqpType === "ERC" || node.isClick == 0 || !node.hasConfig) && node.eqpType !== "MONITOR") {
      node.disabled = true;
    }
    if (node?.children?.length) {
      node.children.forEach(item => filterNodeIsChecked(item));
    }
  };
  if (treeDataLeft.value?.length) {
    treeDataLeft.value.forEach(item => filterNodeIsChecked(item));
  }
  treeDataLeftFltter = flattenDataByKeys(data, "code");
};
// 树添加清除选中按钮
const resetCheckLeft = () => {
  filterTextLeft.value = "";
  const selectedNodes = document.querySelectorAll(".is-current");
  selectedNodes.forEach(element => {
    element.classList.remove("is-current");
  });
};
// 打开或者关闭左侧树
const openOrCloseTreeLeft = type => {
  if (type == "close") {
    isTreeOpen.value = false;
    let nodes = treeRef.value.store._getAllNodes();
    nodes.forEach(item => {
      item.expanded = false;
    });
  } else if (type == "open") {
    isTreeOpen.value = true;
    let nodes = treeRef.value.store._getAllNodes();
    nodes.forEach(item => {
      item.expanded = true;
    });
  }
};
// 过滤树数据
const filterNode = (query: string, node) => {
  if (!query) return true;
  return node.name!.indexOf(query) !== -1 || node.code?.indexOf(query) !== -1 || node.path?.includes(query);
};
// 打开弹窗
const openDialog = async () => {
  done.value = true;
  await queryTree();
  done.value = false;
};
// 关闭弹窗
const closeDialog = () => {
  emits("closeDialog");
  treeRef.value.setExpandedKeys([]);
  clearSelection();
};
// 提交
const handleSubmit = async () => {
  const sel = flattenDataByKeys(props.selected, "itemCode");
  checkedNodesArr.value.forEach(item => {
    const { itemCode } = item;
    if (sel[itemCode]) {
      item.id = sel[itemCode].id;
    }
  });
  const diff = diffByKey(props.selected, checkedNodesArr.value);
  if (diff.length) {
    const res = await delTableId({ ids: diff });
  }
  if (checkedNodesArr.value.length > 0) {
    isLoading.value = true;

    const data = await saveOrUpdateBatch(checkedNodesArr.value);
    isLoading.value = false;
  } else {
    PxMessage.warning("请选择节点");

    return;
  }

  clearSelection();
  PxMessage.success("新增成功");
  emits("closeDialog");
  emits("addEquipGroupSelect", props.routeCode);
};
// 处理复选框选中
const handleCheck = (checkedNode, { checkedNodes }) => {
  let checked = {};

  checkedNodes.forEach(node => {
    checked[node.id] = true;
  });
  checkedNodesArr.value = checkedNodes.map(item => ({
    itemName: item.name,
    itemCode: item.code,
    routeCode: props.routeCode,
    itemType: item.eqpType ? item.eqpType : item.type,
    facCode: item.facCode,
    remark: item.rtspUrl ? item.rtspUrl : "",
    zhPath: getPath(item?.path?.split("@"))
  }));
};
function getPath(pathArr) {
  let newPaths = [];
  if (pathArr && pathArr.length > 0) {
    pathArr.forEach(item => {
      if (treeDataLeftFltter[item]) {
        newPaths.push(treeDataLeftFltter[item].name);
      }
    });
  }
  return newPaths.join("/");
}
// 处理删除
const handleDelete = index => {
  const deletedId = checkedNodesArr.value[index].itemCode;

  // 从右侧删除
  checkedNodesArr.value.splice(index, 1);

  // 同步取消树的勾选状态
  const checkedKeys = treeRef.value.getCheckedKeys();
  const newKeys = checkedKeys.filter(key => key !== deletedId);
  treeRef.value.setCheckedKeys(newKeys);
};

// 处理路径
//扁平化处理
function flattenDataByKeys(data, keys) {
  const keyArray = keys.split(" ");
  function recursiveFlatten(obj, result = {}) {
    if (Array.isArray(obj)) {
      obj.forEach(item => recursiveFlatten(item, result));
    } else if (typeof obj === "object" && obj !== null) {
      let hasKey = keyArray.some(key => obj.hasOwnProperty(key));
      let resultKey = keyArray
        .map(key => obj[key])
        .filter(Boolean)
        .join("_");

      if (hasKey && resultKey) {
        result[resultKey] = obj;
      }

      for (let key in obj) {
        recursiveFlatten(obj[key], result);
      }
    }
    return result;
  }

  return recursiveFlatten(data);
}
//清除已选
const clearSelection = () => {
  checkedNodesArr.value = [];
  treeRef.value.setCheckedKeys([]);
};
/**
 * 递归收集目标 key 的值
 * @param {Array<Object>} target  树形数组对象
 * @param {string}         key    需要提取值的字段名
 * @param {number}         depth  访问深度上限，默认 1
 * @returns {Array<*>}            由 key 对应值组成的新数组
 */
function collectValues(target, key, depth = 1) {
  const result = [];

  function traverse(nodes, currentDepth) {
    if (!Array.isArray(nodes) || currentDepth > depth) return;

    for (const node of nodes) {
      if (Object.prototype.hasOwnProperty.call(node, key)) {
        result.push(node[key]);
      }
      if (node.children && currentDepth < depth) {
        traverse(node.children, currentDepth + 1);
      }
    }
  }

  traverse(target, 1);
  return result;
}
/**
 * Find the symmetric difference of key‑values between two arrays of objects.
 * @param {Object[]} source   – reference list
 * @param {Object[]} target   – list that may add or drop items
 * @param {string}   [key=id] – property used as the identity
 * @returns {Array}           – values that exist in only one input
 */
function diffByKey(source = [], target = [], key = "id") {
  // Collect present key‑values into Sets (fast O(1) look‑ups) :contentReference[oaicite:0]{index=0}
  const sKeys = new Set(source.filter(o => o?.[key] !== undefined).map(o => o[key]));
  const tKeys = new Set(target.filter(o => o?.[key] !== undefined).map(o => o[key]));

  // Symmetric difference: (s − t) ∪ (t − s)
  const onlyInSource = [...sKeys].filter(v => !tKeys.has(v));
  const onlyInTarget = [...tKeys].filter(v => !sKeys.has(v));
  return [...onlyInSource, ...onlyInTarget];
}

function filterTree(tree, type, filter) {
  return tree
    .map(node => {
      if (node.type !== type) {
        // 非指定 type 的节点，原样保留
        return { ...node, children: node.children ? filterTree(node.children, type, filter) : undefined };
      }

      let match = true;
      for (const key in filter) {
        if (node[key]) {
          if (Array.isArray(filter[key])) {
            if (!filter[key].includes(node[key])) {
              match = false;
              break;
            }
          } else if (node[key] !== filter[key]) {
            match = false;
            break;
          }
        }
      }

      if (match) {
        const newNode = { ...node };
        if (node.children) {
          newNode.children = filterTree(node.children, type, filter);
        }
        return newNode;
      }

      return null; // 被筛掉的节点
    })
    .filter(node => node !== null); // 过滤掉 null 节点
}
</script>
<style lang="scss" scoped>
@import url("@/views/erc/scss/table-flex-list.scss");

.equip-dialog {
  .equip-dialog-footer {
    margin-top: 30px;
    text-align: right;
  }
}

.equip-tree-wrap {
  height: 450px;
}

.equip-tree-content {
  display: flex;
}

:deep(.no-border-table td, :deep(.no-border-table th)) {
  border: none !important;
}
</style>
